package com.jackrain.nea.fc.cp.adutils;


import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.util.TypeUtils;
import com.jackrain.nea.config.PropertiesConf;
import com.jackrain.nea.exception.NDSException;
import com.jackrain.nea.util.ApplicationContextHandle;
import lombok.extern.slf4j.Slf4j;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;
import java.util.Hashtable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by ZCY on 2017/12/1.
 * AD域新增组织
 */
@Slf4j
public class AdOrganization {
    public static DirContext ctx = null;
    public static String groupname;
    public static Hashtable<String, String> env = new Hashtable<String, String>();


    public static void ldapload() {

        try {
            PropertiesConf pconf = ApplicationContextHandle.getBean(PropertiesConf.class);
            String ldapurl = pconf.getProperty("ldap.urls");
            String adminName = pconf.getProperty("ad.ssl.admin");
            String adminpassword = pconf.getProperty("ad.ssl.password");
            groupname = pconf.getProperty("ad.upper.organization");

            env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
            env.put(Context.SECURITY_AUTHENTICATION, "simple");
            env.put(Context.SECURITY_PRINCIPAL, adminName);
            env.put(Context.SECURITY_CREDENTIALS, adminpassword);
            env.put(Context.PROVIDER_URL, ldapurl);
        } catch (Exception ef) {
            log.error("获取配置文件失败:" + ef, ef);
            throw new NDSException("获取配置文件失败:" + ef, ef);
        }

        try {
            ctx = new InitialDirContext(env);
            log.info("通过连接LDAP进行认证");
        } catch (Exception e) {
            log.error("登录的用户名或密码错误，无法通过LDAP认证:" + e, e);
            throw new NDSException("登录的用户名或密码错误，无法通过LDAP认证:" + e, e);
        }


    }

    public static boolean delorg(JSONObject userobj, String orgtype) {
        String id = userobj.getString(orgtype);
        Attributes attributes = searchOrg(orgtype, id);
        if (attributes == null) {
            return false;
        } else {
            String oldorglink = TypeUtils.castToString(attributes.get("distinguishedName"));
            oldorglink = oldorglink.substring(oldorglink.indexOf(":") + 2, oldorglink.length());
            deleteOrg(oldorglink);
            return true;
        }

    }

    public static boolean deleteOrg(String ldapGroupDN) {

        Boolean createresult = false;
        Attributes attrdel = null;
        try {
            attrdel = ctx.getAttributes(ldapGroupDN);
        } catch (Exception e) {
//            e.printStackTrace();
            log.error(e + "===该组织目录已不存在");
//            closeCtx();
//            throw new NDSException("该组织目录不存在");
        }
        log.info(ldapGroupDN + "====存在该组织目录====");
        try {
            ctx.destroySubcontext(ldapGroupDN);
            createresult = true;
            return createresult;
        } catch (Exception ex) {
            ex.printStackTrace();
            log.error("删除失败，该组织目录下还有子目录，请先删除子目录:" + ex, ex);
            throw new NDSException("删除失败，该组织目录下还有子目录，请先删除子目录:" + ex, ex);
        } finally {
            closeCtx();
        }
    }

    public static boolean getOrg(JSONObject orgobj, String orgtype, JSONObject groupobj) {
        String id = orgobj.getString(orgtype);
        String ou = orgobj.getString("ou");
        String orgLink = orgobj.getString("ORGLINK");
        if (StringUtils.isEmpty(ou)) {
            throw new NDSException("组织名为空");
        }
        Attributes attributes = searchOrg(orgtype, id);
        if (attributes == null) {
            //新增组织
            createOrg(orgLink, orgtype, groupobj);
            return true;
        } else {
            String oldorglink = TypeUtils.castToString(attributes.get("distinguishedName"));
            oldorglink = oldorglink.substring(oldorglink.indexOf(":") + 2, oldorglink.length());
            //修改组织
            StringBuffer neworgbuf = new StringBuffer("");
            neworgbuf.append(orgLink).append(",").append(groupname);
            String neworg = neworgbuf.toString();
            if (!oldorglink.equals(neworg)) {
                modifyOrg(oldorglink, orgLink, "wWWHomePage", groupobj);
                return false;
            }
            return true;
        }

    }

    public static Attributes searchOrg(String orgtype, String id) {

        String returnedAtts[] = {
                "ou", "name", "wWWHomePage", "telephoneNumber", "distinguishedName"
        };
        SearchControls searchCtls = new SearchControls();
        searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        searchCtls.setReturningAttributes(returnedAtts);
//        String ou,String orgtype,String id
        StringBuffer filterbuf = new StringBuffer("(&");
        filterbuf.append("(").append(orgtype).append("=").append(id).append(")");
        filterbuf.append("(objectClass=organizationalUnit))");
        //  定义条件
        String searchFilter = filterbuf.toString();
        String searchBase = groupname;
        Attributes attributes = null;
        try {
            //  执行查询
            NamingEnumeration<SearchResult> answer = ctx.search(searchBase, searchFilter, searchCtls);
            if (answer.hasMoreElements()) {
                SearchResult sr = (SearchResult) answer.next();
                attributes = sr.getAttributes();

            } else {
                log.info("AD域中不存在该组织");
                return attributes;
            }
        } catch (Exception e) {
            log.info("AD域中不能存在该组织");
            return null;

        }
        return attributes;

    }

    public static boolean modifyOrg(String beforeorg, String afterorg, String orgtype, JSONObject groupidobj) {


        if (StringUtils.isEmpty(beforeorg)) {
            throw new NDSException("原组织目录为空");
        }
        if (StringUtils.isEmpty(afterorg)) {
            throw new NDSException("新组织目录为空");
        }
        Integer newstart = afterorg.indexOf(",");
        if (newstart > 0) {
            String neworg = afterorg.substring(newstart + 1, afterorg.length());
            JSONObject newgroupobj = new JSONObject(true);
            JSONObject faobj = new JSONObject(true);
            String[] falterall = afterorg.split(",");
            for (int i = 1; i < falterall.length; i++) {
                String name = falterall[i];
                String nameorg = name.substring(name.indexOf("=") + 1, name.length());
//                name.substring(nameorg)
                String orgupid = groupidobj.getString(nameorg + i);
                newgroupobj.put(nameorg + (i - 1), orgupid);
            }

            createOrg(neworg, orgtype, newgroupobj);
        }
        try {
            ctx.getAttributes(beforeorg);
        } catch (Exception e) {
            throw new NDSException("原有的组织目录" + beforeorg + "不存在", e);
        }
        StringBuffer afterbuf = new StringBuffer(afterorg);
        afterorg = afterbuf.append(",").append(groupname).toString();
        try {
            ctx.rename(beforeorg, afterorg);
        } catch (Exception el) {
            log.error("新组织目录" + afterorg + "已存在:" + el.getMessage(), el);
            throw new NDSException("新组织目录" + afterorg + "已存在:" + el.getMessage(), el);
        }

        return true;
    }

    public static boolean addorg(String ldapGroupDN, String Orgtype, String id) {
        if (StringUtils.isEmpty(ldapGroupDN)) {
            throw new NDSException("组织目录路径为空");
        }

        ldapGroupDN=ldapGroupDN.replaceAll("[/\\\\]","|");
//        ldapGroupDN=ldapGroupDN.replace("\\\\","|");

        try {
        /*
         * 查找是否已经存在指定的OU条目
         * 如果存在，则打印OU条目的属性信息
         * 如果不存在，则程序会抛出NamingException异常，进入异常处理
         */
            ctx.getAttributes(ldapGroupDN);
            log.info(ldapGroupDN + "====存在该组织目录====");
            return false;
        } catch (Exception e) {
            log.info(ldapGroupDN + "===不存在该目录,现进行新增目录===");

            // TODO 没有找到对应的Group条目，新增Group条目

            //创建objectclass属性
            Attribute objclass = new BasicAttribute("objectclass");
            objclass.add("top");
            objclass.add("organizationalUnit");
            //创建cn属性
            Integer start = ldapGroupDN.indexOf("=");
            Integer end = ldapGroupDN.indexOf(",");

            String OUNAME = ldapGroupDN.substring(start + 1, end);


            log.info(OUNAME + "===OUNAME===");
            Attribute cn = new BasicAttribute("OU", OUNAME);
            //创建Attributes，并添加objectclass和cn属性
            Attributes attrs = new BasicAttributes();
            attrs.put(objclass);
            attrs.put(cn);

            id=id.replaceAll("[/\\\\]","|");

            attrs.put(Orgtype, id);
            //将属性绑定到新的条目上，创建该条目
            try {
                ctx.bind(ldapGroupDN, null, attrs);
                log.info("====部门目录创建成功===");
            } catch (Exception etx) {
                etx.printStackTrace();
                log.error("部门目录创建失败:"+id + etx, etx);
                throw new NDSException("部门的目录创建失败:"+">>"+id+etx, etx);
            }
        }
//        }

        return true;
    }

    //创建/绑定组织
    public static boolean createOrg(String grouporg, String orgtype, JSONObject groupidobj) {

        String ldapGroupDN = null;
        if (StringUtils.isEmpty(grouporg)) {
            throw new NDSException("原组织目录为空");
        }
        Integer start = grouporg.indexOf(",");
        Boolean result = false;
        if (start < 0) {
            StringBuffer cretebuf = new StringBuffer(grouporg);
            grouporg = cretebuf.append(",").append(groupname).toString();
            String orgnams = grouporg.substring(grouporg.indexOf("=") + 1, grouporg.length());
            String id = groupidobj.getString(orgnams + 0);
            result = addorg(grouporg, orgtype, id);
            return result;
        } else {
            String group = groupname;
            String[] fatherdir = grouporg.split(",");
            for (int i = fatherdir.length - 1; i >= 0; i--) {
                StringBuffer groupbuf = new StringBuffer("");
                grouporg = fatherdir[i];
                String name = grouporg.substring(grouporg.indexOf("=") + 1, grouporg.length()) + i;
                String id = groupidobj.getString(name);
                groupbuf.append(grouporg).append(",").append(group);
                group = groupbuf.toString();
                log.info(groupbuf + "====groupbuf=====");
                ldapGroupDN = groupbuf.toString();
//                String name=ldapGroupDN.substring(ldapGroupDN.indexOf("=")+1,ldapgr)
                if ("telephoneNumber".equals(orgtype)) {
                    if (i == 0) {
                        result = addorg(ldapGroupDN, orgtype, id);
                    } else {
                        result = addorg(ldapGroupDN, "wWWHomePage", id);
                    }
                } else {
                    result = addorg(ldapGroupDN, orgtype, id);
                }
                if (i == 0) {
                    return result;
                }

            }
        }


        return true;
    }


    // 关闭LDAP服务器连接
    public static void closeCtx() {
        try {
            ctx.close();
        } catch (NamingException ex) {
            log.error("====关闭LDAP连接失败" + ex, ex);
        }
    }

    private static String htmlToText(String str) {
        String regEx = "[\\\\/]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        String findChar = "";
        while (m.find()) {
            findChar = m.group();
            break;
        }
        return m.replaceAll("\\\\\\" + findChar).trim();
    }


}
